package com.echo.distributedlock.aspect;

import com.echo.distributedlock.annotation.DistributedLock;
import com.echo.distributedlock.service.LockService;
import com.echo.distributedlock.utils.KeyUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.locks.Lock;

/**
 * @author lmy
 */
@Order(0)
@Aspect
@Component
public class DistributedLockAspect {

    @Resource
    private LockService lockService;

    @Pointcut("@annotation(distributedLock)")
    public void pointCut(DistributedLock distributedLock) {
    }

    @Around(value = "pointCut(distributedLock)", argNames = "point,distributedLock")
    public Object around(ProceedingJoinPoint point, DistributedLock distributedLock) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        String name = methodSignature.getName();
        String[] parameterNames = methodSignature.getParameterNames();
        Object[] args = point.getArgs();
        String key = KeyUtil.generateKey(parameterNames, name, distributedLock.key(), args);
        Lock lock = lockService.getLock(key);
        if (lock.tryLock()) {
            try {
                return point.proceed();
            } finally {
                lock.unlock();
            }
        } else {
            throw new IllegalArgumentException("当前任务执行中");
        }
    }
}
